package vinnichenko.lab3;

/**Own packages*/
import vinnichenko.lab3.database.*;
import vinnichenko.lab3.exception.*;

/**Java core packages*/
import java.io.*;
import java.sql.*;
import java.util.*;

/**Java extension packages*/
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import javax.naming.*;
import javax.sql.*;

/**Other packages*/
import org.w3c.dom.*;
import org.xml.sax.*;
import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;

/**Servlet to allow add new users into database.
 * @author Igor Vinnichenko
 * @version 1.0
 */
public class AddNewPersonServlet extends HttpServlet {
    /**UID*/
    private static final long serialVersionUID = 6L;

    /**Declaration and creation logger.*/
    static Logger logger = Logger.getLogger(AddNewPersonServlet.class);

    /**Employee database object*/
    private EmployeeDB employeeDB;

    /**Department database object*/
    private DepartmentDB deptDB;

    /**Servlet initialization method.*/
    public void init()throws ServletException{
        /**Get DAO attribute from servlet context.*/
        EmployeesDAO empDAO = (EmployeesDAO)getServletContext().getAttribute("eDB");

        /**If DAO doesn't exist then throw exception.*/
        if( empDAO == null){
            throw new UnavailableException("Couldn't get database.");
        }

        /**Create database objects and give it pointers to database*/
        employeeDB = new EmployeeDB();
        employeeDB.setDatabase( empDAO );

        deptDB = new DepartmentDB();
        deptDB.setDatabase( empDAO );

        /**Report success message into log.*/
        logger.info("AddNewPersonServlet initialization successful.");
    }

    /**Method called when servlet is near to be destroyed*/
    public void destroy(){
        /**Set database objects to nulls. Garbage collector will do all work for us.*/
        employeeDB = null;
        deptDB = null;
        /**Report into log.*/
        logger.info("AddNewPersonServlet destroyed.");
    }

    /**Method to process 'get' request.
     * Get request gets from database only information about possible values
     * of managers and departments and fill ComboBoxes with them. Other fields
     * of form must be empty for new values.
     * @param request - servlet request.
     * @param response - servlet response.
     * @throws ServletException, IOException.
     */
    protected void doGet( HttpServletRequest request, HttpServletResponse response )
        throws ServletException, IOException {
        
        logger.debug("AddNewPersonServlet, method 'Get' was called.");

        /**Set content type - text/html*/
        response.setContentType( "text/html" );
        /**Getting writer for output data*/
        PrintWriter out = response.getWriter();

        try{
            /** Get a DocumentBuilderFactory for creating
             * a DocumentBuilder (i.e., an XML parser)*/
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

            /**Get a DocumentBuilder for building the DOM tree*/
            DocumentBuilder builder = factory.newDocumentBuilder();

            /**Create a new Document (empty DOM tree)*/
            Document messageDocument = builder.newDocument();

            /**Prepare XML document with empty data but with possible
             * values from database to fill ComboBoxes and append to Document*/
            Element employeeElement = prepareXMLDoc(messageDocument);
            messageDocument.appendChild( employeeElement );

            /**Open InputStream for XSL document*/
            InputStream xslStream = getServletContext().getResourceAsStream( "/addnewemployee.xsl" );

            /**Transform XML document using XSLT*/
            XMLTransformer.transform( messageDocument, xslStream, out );
        }catch ( ParserConfigurationException pcException ) { 
            /**catch XML parser exceptions*/
            logger.error(StackWriter.getFullStackTrace( pcException ));
            getServletContext().setAttribute("javax.servlet.error.exception", (Throwable)pcException );
            throw new ServletException( pcException );
        }catch ( DatabaseConnectException e ){
            logger.error(StackWriter.getFullStackTrace( e ));
            getServletContext().setAttribute("javax.servlet.error.exception", (Throwable)e );
            throw new ServletException( e );
        }catch ( DepartmentsNotFoundException e ) {
            logger.error(StackWriter.getFullStackTrace( e ));
            getServletContext().setAttribute("javax.servlet.error.exception", (Throwable)e );
            throw new ServletException( e );
        }catch ( XSLTTransformingException e ) { 
            logger.error(StackWriter.getFullStackTrace( e ));
            getServletContext().setAttribute("javax.servlet.error.exception", (Throwable)e );
            throw new ServletException( e );
        }

        /**Flush and close output.*/
        out.flush();
        out.close();
    }   

    /**Method to process 'post' request.
     * Post request gets from form information about new employee
     * and insert it into database.
     * @param request - servlet request.
     * @param response - servlet response.
     * @throws ServletException, IOException.
     */
    protected void doPost( HttpServletRequest request, HttpServletResponse response )
        throws ServletException, IOException {

        logger.debug("AddNewPersonServlet, method 'Post' was called.");

        /**Content type will be text/html*/
        response.setContentType( "text/html" );
        /**Getting writer for output*/
        PrintWriter out = response.getWriter();

        try{
            /**Get parameters from request.*/
            String ename = request.getParameter( "ename" );
            String job = request.getParameter( "job" );
            Integer mgr = Integer.valueOf( request.getParameter( "mgr" ) );
            Integer deptno = Integer.valueOf( request.getParameter( "deptno" ) );
            Float sal = Float.valueOf( request.getParameter( "sal" ) );
            Float comm = Float.valueOf( request.getParameter( "comm" ) );
            java.sql.Date hiredate = java.sql.Date.valueOf( request.getParameter( "hiredate" ) );

            EmployeeInfo emp = employeeDB.addNewEmployee( ename, job, mgr, deptno, sal, comm, hiredate);

            /** Get a DocumentBuilderFactory for creating a DocumentBuilder*/
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

            /** Get a DocumentBuilder for building the DOM tree*/
            DocumentBuilder builder = factory.newDocumentBuilder();

            /** Create a new Document (empty DOM tree)*/
            Document messageDocument = builder.newDocument();

            /** Get XML from EmployeeBean and append to Document*/
            Element employeeElement = emp.getXML( messageDocument );
            messageDocument.appendChild( employeeElement );

            /** Open InputStream for XSL document*/
            InputStream xslStream = getServletContext().getResourceAsStream( "/readonlyinfo.xsl" );

            /** transform XML document using XSLT*/
            XMLTransformer.transform( messageDocument, xslStream, out );
        }catch ( ParserConfigurationException pcException ) { 
            /**Catch XML parser exceptions*/
            logger.error(StackWriter.getFullStackTrace( pcException ));
            getServletContext().setAttribute("javax.servlet.error.exception", (Throwable)pcException );
            throw new ServletException( pcException );
        }catch ( DatabaseConnectException e ){
            logger.error(StackWriter.getFullStackTrace( e ));
            getServletContext().setAttribute("javax.servlet.error.exception", (Throwable)e );
            throw new ServletException( e );
        }catch ( EmployeeNotFoundException e ) { 
            logger.error(StackWriter.getFullStackTrace( e ));
            getServletContext().setAttribute("javax.servlet.error.exception", (Throwable)e );
            throw new ServletException( e );
        }catch ( NumberFormatException e ) { 
            logger.error(StackWriter.getFullStackTrace( e ));
            getServletContext().setAttribute("javax.servlet.error.exception", (Throwable)e );
            throw new ServletException( e );
        }catch ( XSLTTransformingException e ) { 
            logger.error(StackWriter.getFullStackTrace( e ));
            getServletContext().setAttribute("javax.servlet.error.exception", (Throwable)e );
            throw new ServletException( e );
        }

        /**Close output stream.*/
        out.flush();
        out.close();
    }   

    /**Method for preparing XML document for further transformation into html data.
     * XML data contains all possible values of dapartment names and all
     * possible managers' names.
     * @param document - document into which need to write prepared data.
     * @return elemwnt with xml data.
     */
    private Element prepareXMLDoc(Document document)
        throws EmployeesNotFoundException, DepartmentsNotFoundException, DatabaseConnectException{

        /**Create 'employee' element as root.*/
        Element employee = document.createElement( "employee" );

        /**List of possible managers*/
        List<EmployeeInfo> possibleManagers = employeeDB.getHierarchyList();

        for(EmployeeInfo possibleManager : possibleManagers){
            /**Create xml data and add it to root as child branch*/
            Element temp = document.createElement( "mgr" );
            temp.setAttribute("id", String.valueOf( possibleManager.getEmployeeNo() ) );
            temp.setAttribute("name", possibleManager.getEmployeeName() );
            temp.appendChild( document.createTextNode( String.valueOf( possibleManager.getEmployeeNo() ) ) );
            employee.appendChild( temp );
        }

        /**List of all departments' names.*/
        List<DepartmentInfo> possibleDepts = deptDB.getDepartmentsList();

        for(DepartmentInfo possibleDept : possibleDepts){
            /**Create xml data and add it to root as child branch*/
            Element temp = document.createElement( "deptno" );
            temp.setAttribute("id", String.valueOf( possibleDept.getDeptNo() ) );
            temp.setAttribute("name", possibleDept.getDeptName() );
            temp.appendChild( document.createTextNode( String.valueOf( possibleDept.getDeptNo() ) ) );
            employee.appendChild( temp );
        }

        /**And return XML element containing prepared data.*/ 
        return employee;
    }
}
